package com.eric.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eric.domain.bso.UserBso;
import com.eric.domain.dto.SysUserDto;
import com.eric.domain.po.SysUser;
import com.eric.domain.po.UserPermission;
import com.eric.domain.po.UserRole;
import com.eric.domain.vo.SysUserVo;
import com.eric.mapper.SysUserMapper;
import com.eric.service.ISysUserService;
import com.eric.service.IUserPermissionService;
import com.eric.service.IUserRoleService;
import com.eric.utils.RegUtil;
import com.eric.utils.ServerBASEURL;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.DeleteJoinWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import static com.eric.utils.Constant.PAGE_CURRENT;
import static com.eric.utils.Constant.PAGE_SIZE;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 新哥
 * @since 2024-03-12
 */
@Service
@Transactional
@RequiredArgsConstructor
public class SysUserServiceImpl extends MPJBaseServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
    //   定义时间格式
    SimpleDateFormat sdf=new SimpleDateFormat("/yyyy/MM/dd/");
    @Value("${file.location}")
    String fileLocation;

    private final IUserRoleService userRoleService;
    private final IUserPermissionService userPermissionService;
    @Override
    @Transactional
//  todo  修改一个数据库中的user===重新整理一下这个接口逻辑
    public SaResult modifyUser(SysUserDto userDtoIn,MultipartFile profilePhoto,HttpServletRequest request) {


//       处理对象中null类型字符串，和处理字符串两端多余的空字符串
        SysUserDto userDto= TrimStrNull(userDtoIn);

//       正则表达式处理字符串格式
        if (userDto.getPassword()!=null){
            boolean matchPassword = ReUtil.isMatch(RegUtil.passwordRegex,userDto.getPassword() );
            if (!matchPassword){
                return SaResult.error("密码格式不符合要求");
            }
        }
        if (userDto.getRealName()!=null){
            boolean matchRealName = ReUtil.isMatch(RegUtil.realNameRegx, userDto.getRealName());
            if (!matchRealName){
                return SaResult.error("姓名格式不符合要求");
            }
        }
        if (userDto.getEmail()!=null){
            boolean matchEmail = ReUtil.isMatch(RegUtil.emailRegx, userDto.getEmail());
            if (!matchEmail){
                return SaResult.error("邮件格式不符合要求");
            }
        }
        if (userDto.getPhone()!=null){
            boolean matchPhone = ReUtil.isMatch(RegUtil.phoneRegex, userDto.getPhone());
            if (!matchPhone){
                return SaResult.error("电话号码格式不符合要求");
            }
        }

//        通过用户登录名查询数据库是否有数据
        SysUser user = query().eq("id", userDto.getId()).one();
//        如果没有，返回错误信息
        if (BeanUtil.isEmpty(user)){
            return SaResult.error("没有此用户，请核实后再次提交");
        }

        String trimPassword = userDto.getPassword();
//        如果传进来的password为空
        if (StrUtil.isBlank(trimPassword)){
//           如果密码是null或者“”，把password设定为null，是的update是不更改这个password
//           userDto.setPassword(null);
//            如果前端传来的图片为空
            if (profilePhoto==null){
//                userDto.setPassword(null);
//        把userDto转换为SysUser
                SysUser sysUser = BeanUtil.copyProperties(userDto, SysUser.class);
//                不能修改用户名，所以都需要把loginname设定为Null
                sysUser.setLoginName(null);
//          getLoginRealName是获取到当前登录用户的真实姓名
                String loginName = getLoginRealName();

//            把获取到的realName设定为表中的Create_by字段
                sysUser.setLastUpdateBy(loginName);
//        修改数据库
                boolean update = updateById(sysUser);
                return update?SaResult.ok("update succeed(no password)"):SaResult.error("wrong");
            }
//            下面是当profilePhoto不为空，即意味着修改头像，这样子应该调用fileOperation方法处理文件
//            把前端传来userDto对象转换成userBso对象
            UserBso userBso = BeanUtil.copyProperties(userDto, UserBso.class);
//            通过userBso获取到文件url
            String fileUrl = fileOperation(userBso, profilePhoto, request);
//             把userDto转换为sysUser对象
            SysUser sysUser=BeanUtil.copyProperties(userDto,SysUser.class);
//            sysUser对象的profilePhoto值设定为fileUrl
            sysUser.setProfilephoto(fileUrl);
//            把loginname在这里设定为Null,而不是从一开始，主要是在方法fileOperation需要调用logiinname;
            sysUser.setLoginName(null);
            sysUser.setLastUpdateBy(getLoginRealName());
            boolean update = updateById(sysUser);
            return update?SaResult.ok("update succeed(no password)"):SaResult.error("wrong");
        }

        String newPw = BCrypt.hashpw(userDto.getPassword(), BCrypt.gensalt());
        userDto.setPassword(newPw);
        UserBso userBso = BeanUtil.copyProperties(userDto, UserBso.class);
        String fileUrl = fileOperation(userBso, profilePhoto, request);
        SysUser sysUser=BeanUtil.copyProperties(userDto,SysUser.class);
        sysUser.setProfilephoto(fileUrl);
        sysUser.setLoginName(null);
        String loginRealName = getLoginRealName();
        sysUser.setLastUpdateBy(loginRealName);
        boolean update = updateById(sysUser);
//        退出当前登录用户
        StpUtil.logout(userDto.getId());

        return update?SaResult.ok("update succeed(password)"):SaResult.error("wrong");
    }



    @Override
    @Transactional
//    新添加一个user进数据库，包含头像
    public SaResult saveOneUser(UserBso userBsoIn, MultipartFile profilePhoto, HttpServletRequest request) {




//        通过loginNamev查询数据库中是否有相关数据
        List<SysUser> newUsers = query().eq("loginname", userBsoIn.getLoginName()).list();
        if (!newUsers.isEmpty()){
            return SaResult.error("用户已存在，请用另外用户名注册");
        }
        UserBso userBso = trimStrNullUserBso(userBsoIn);

//        使用正则表达式校验
        boolean matchLoginName = ReUtil.isMatch(RegUtil.loginNameRegx, userBso.getLoginName());
        if (!matchLoginName){
            return SaResult.error("登录名应该是4~16位数字，字面，下划线，减号组成");
        }

//      正则表达式判断密码格式是否正确
        boolean matchPassword = ReUtil.isMatch(RegUtil.passwordRegex,userBso.getPassword());
        if (!matchPassword){
            return SaResult.error("密码应由数字、小写、大写字母、特殊字符任意三个组成，且长度大于8");
        }
//        对传进来的密码进行hash加密
        String hashpw = BCrypt.hashpw(userBso.getPassword(), BCrypt.gensalt());
//        把加密后的密码放进userDto对象中
        userBso.setPassword(hashpw);
        if (profilePhoto!=null){
            System.out.println("profilephoto为空");

        }
//        finOperations方法把文件放进服务器硬盘上，并返回一个文件的全名称地址
        String profilePhotoPath = fileOperation(userBso,profilePhoto, request);
//        把userDto对象转换为sys_user对象
        SysUser sysUser = BeanUtil.copyProperties(userBso, SysUser.class);
        sysUser.setProfilephoto(profilePhotoPath);
        String loginRealName = getLoginRealName();
        sysUser.setCreateBy(loginRealName);


       


//        sys_user对象写入数据库
        boolean save = save(sysUser);

//        从这里，返回一个回前端
        if (!save){
            return SaResult.data("wrong");
        }

        SysUser savedUser = query().eq("loginName", sysUser.getLoginName()).one();

        return SaResult.data(savedUser.getId());



//        添加user_role表和user_permission表的默认设置，默认的是这两个表中，role的默认值是visitor，permission默认值是visit
       /* UserRole userRole = new UserRole();
        userRole.setRoleId(5);
        userRole.setUserId(sysUser.getId());
        userRoleService.save(userRole);
        UserPermission userPermission=new UserPermission();
        userPermission.setUserId(sysUser.getId());
        userPermission.setPermissionId(5);
        userPermissionService.save(userPermission);*/
//        还需要写入这个Location数据，但在另外一个接口（关于Location类中添加）
        /*return save?SaResult.ok("成功"):SaResult.error("failed");*/
    }

    /*
     * 分页获取数据库中的用户
     * */
    @Override
    public SaResult getAllOnPage(Integer current, Integer pageSize) {
        if (current==null){
            current=PAGE_CURRENT;
        }
        if (pageSize==null){
            pageSize=PAGE_SIZE;
        }
        Page<SysUser>page=new Page<>(current,pageSize);
//        分页查询deleted=0,status=1的数据库记录
        List<SysUser> sysUserList = query().eq("status", 1).orderByDesc("update_time").page(page).getRecords();
        List<SysUserVo> userVoList = BeanUtil.copyToList( sysUserList, SysUserVo.class);
        return SaResult.data(userVoList);
    }

    @Override
    @Transactional
    /*
     * 通过User的id批量删除用户
     * */
    public SaResult deleteByIds(List<Integer> ids) {
        List<SysUser> userList = listByIds(ids);
        if (userList.size()!=ids.size()){
            return SaResult.error("id不存在，请检查后再试");
        }
        boolean b = removeBatchByIds(userList);
        return b?SaResult.ok("succeed!"):SaResult.error("wrong");
    }

    @Override
    public SaResult getAllByNameService(String name, Integer current, Integer pageSize) {
        if (current==null){
            current=PAGE_CURRENT;
        }
        if (pageSize==null){
            pageSize=PAGE_SIZE;
        }
        String nameTrim = StrUtil.trim(name);
        if (nameTrim==null){
            return SaResult.error("姓名不能为空");
        }
        Page<SysUser>page=new Page<>(current,pageSize);
        List<SysUser> sysUserList = query().like("realname", name)
                .orderByDesc("update_time").page(page).getRecords();
        List<SysUserDto> sysUserDtoList = BeanUtil.copyToList(sysUserList, SysUserDto.class);
        return SaResult.data(sysUserDtoList);
    }

    //    修改了头像图片地址
    @Override
    public SaResult getUsetDetailService() {
        SysUser one = query().eq("id", StpUtil.getLoginId()).one();
        one.setPassword(null);
        String profilephoto = one.getProfilephoto();
        if (profilephoto!=null){
            String newProfilePhoto = ServerBASEURL.BASEURL +profilephoto;
            one.setProfilephoto(newProfilePhoto);
        }
        return SaResult.data(BeanUtil.copyProperties(one, SysUserDto.class));
    }

    //    根据id删除一条数据
    @Override
    public SaResult deleteOne(Integer id) {
        if (id==null||id<=0){
            return SaResult.error("id参数错误");
        }

//     联表删除
        DeleteJoinWrapper<SysUser>wrapper= JoinWrappers.delete(SysUser.class)
                .deleteAll()
                .leftJoin(UserRole.class,UserRole::getUserId,SysUser::getId)
                .leftJoin(UserPermission.class,UserPermission::getUserId,SysUser::getId)
                .eq(SysUser::getId,id);
        boolean b = deleteJoin(wrapper);


        return SaResult.ok("succeed!");
    }

    @Override
    public SaResult getUserById(Integer id) {
        if (id==null||id<=0){
            return SaResult.error("id参数错误");
        }
        SysUser one = query().eq("id", id).one();
        if (BeanUtil.isEmpty(one)){
            return SaResult.error("id不存在");
        }
        SysUserVo sysUserVo = BeanUtil.copyProperties(one, SysUserVo.class);
        if (!StrUtil.isBlank(sysUserVo.getProfilephoto())){
            sysUserVo.setProfilephoto(ServerBASEURL.BASEURL+sysUserVo.getProfilephoto());
        }
        return SaResult.data(sysUserVo);
    }

//    公共文件存储方法

    private String fileOperation(UserBso userDto, MultipartFile profilePhoto, HttpServletRequest request) {
//        如果参数profilePhoto为空，自动设置头像图片
        if (profilePhoto==null){
//            通过Loginname查询了对象，这里是为了判断执行这个文件操作的方法是在saveOne方法内还是modifyOne方法内
            String loginname = userDto.getLoginName();
            SysUser userQueryByLoginname = query().eq("loginname", loginname).one();
//            如果是saveOne模块，userQueryByLoginname肯定是null
//            如果是modifyOne模块，userQueryByLoginname肯定不是Null
//            判定这是modifyOne模块
            if (!BeanUtil.isEmpty(userQueryByLoginname)){
//          如果原头像已存在，且前端现在表单中file是空，就返回null
                if (!StrUtil.isBlank(userQueryByLoginname.getProfilephoto())){
                    return null;
                }
            }
//             增加默认头像逻辑
            String format = sdf.format(new Date());
//            拼接头像图片文件夹
            String realPath=fileLocation+"/profilePhoto/"+format;
            File folder=new File(realPath);
            if (!folder.exists()){
                folder.mkdirs();
            }
//            采用登录名作为图片文件名
            String  newFileName=userDto.getLoginName()+".jpg";
            File defaultFile=new File(fileLocation+"/profilePhoto/"+"defaultProfilePhoto.jpg");
            File newProfilePhoto=new File(fileLocation+"/profilePhoto/"+format+newFileName);
//            把默认头像图片拷贝到目标路径中
            FileUtil.copy(defaultFile.toPath(), newProfilePhoto.toPath());
            return request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/file"+"/profilePhoto"+format+newFileName;
        }

//        获取文件的原始名称
        String originalFilename = profilePhoto.getOriginalFilename();
//        获取到最后一个“.”在图片文件名中的索引
        int i  = 0;
        if (originalFilename != null) {
            i = originalFilename.lastIndexOf(".");
        }
        String substring;
        String newFileName=null;
        if (originalFilename != null) {
//             把截取文件名的后缀  “.jpg”
            substring = originalFilename.substring(i);
//            重新拼接文件名加.jpg，前缀是登录名，如登录名为eric，整照片的全名就是eric.jpg
            newFileName=userDto.getLoginName()+substring;
        }

        String format = sdf.format(new Date());
//        创建全路径名，不包括服务器的路径
        String realPath=fileLocation+"/profilePhoto"+format;
        File folder=new File(realPath);
        String url;
        if (!folder.exists()){
            folder.mkdirs();
        }
        try {
            if (originalFilename!=null){
                profilePhoto.transferTo(new File(folder,newFileName));
            }
            /*request.getScheme():指服务器访问协议，如http
             * ://拼接http://
             * request>getServerName：服务器地址，如localhost
             * ":"拼接 ： 前面加起来就是http://localhost:
             * request.getServerPort:获取端口号，这里是80,拼接原来的就是http://localhost:80
             * /profilePhoto  就是在服务器硬盘上建立一个文件件，叫做profilePhoto,拼接后就是http://localhost:80/profilePhoto-这句有点不对
             * format :就是那个日期 ，如/2024/03/19,拼接后就是http://localhost:80/profilePhoto/2024/03/19/
             * newFileName 存到硬盘文件的名字，如pikachu.jpg，拼接后就是http://localhost:80/profilePhoto/2024/03/19/pikachu.jpg
             * 但是要注意的是，由于在yml文件中设定了path:profilePhoto，实际上硬盘里目录中是没有profilePhoto这个文件夹得，注意这一点
             * */
            url="/profilePhoto"+format+newFileName;
        }catch (IOException e){
            throw new RuntimeException(e);
        }
        return url;
    }

    //   检测字符串数据，如果是“”就设置为null，以便mp不做修改
    private SysUserDto TrimStrNull(SysUserDto userDtoIn) {
        String loginname = StrUtil.trim(userDtoIn.getLoginName());
        if (StrUtil.isBlank(StrUtil.trim(loginname))){
            userDtoIn.setLoginName(null);
        }
        else {
            userDtoIn.setLoginName(loginname);
        }


        String password =StrUtil.trim(userDtoIn.getPassword());
        if (StrUtil.isBlank(StrUtil.trim(password))){
            userDtoIn.setPassword(null);
        }
        else {
            userDtoIn.setPassword(password);
        }


        String realname =StrUtil.trim(userDtoIn.getRealName());
        if (StrUtil.isBlank(StrUtil.trim(realname))){
            userDtoIn.setRealName(null);
        }
        else {
            userDtoIn.setRealName(realname);
        }


        String email = StrUtil.trim(userDtoIn.getEmail());
        if (StrUtil.isBlank(StrUtil.trim(email))){
            userDtoIn.setEmail(null);
        }
        else {
            userDtoIn.setEmail(email);
        }

        String phone =StrUtil.trim(userDtoIn.getPhone());
        if (StrUtil.isBlank(StrUtil.trim(phone))){
            userDtoIn.setPhone(null);
        }
        else {
            userDtoIn.setPhone(phone);
        }
        return userDtoIn;
    }

    //       检测字符串数据，如果是“”就设置为null，以便mp不做修改
    private UserBso trimStrNullUserBso(UserBso userBso){
        String loginname =StrUtil.trim(userBso.getLoginName()) ;
        if (StrUtil.isBlank(loginname)){
            userBso.setLoginName(null);
        }

        String password =StrUtil.trim(userBso.getPassword()) ;
        if (StrUtil.isBlank(password)){
            userBso.setPassword(null);
        }

        return userBso;
    }

    //  获取当前登录名称并返回对象
    private String getLoginRealName(){
//            通过登录id和userService，获取到用户的realName
        return query().eq("id", Integer.parseInt(StpUtil.getLoginId().toString())).one().getRealName();

    }

}





















